package com.lsh.ofc.provider.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.base.common.model.CommonResult;
import com.lsh.base.common.utils.CollectionUtils;
import com.lsh.ofc.api.dto.OrderDetailDTO;
import com.lsh.ofc.api.dto.OrderHeadDTO;
import com.lsh.ofc.api.service.OrderService;
import com.lsh.ofc.core.constant.Constants;
import com.lsh.ofc.core.entity.OfcCustomer;
import com.lsh.ofc.core.entity.OfcOrderDetail;
import com.lsh.ofc.core.entity.OfcOrderHead;
import com.lsh.ofc.core.enums.*;
import com.lsh.ofc.core.exception.EC;
import com.lsh.ofc.core.handler.MeipiCustomerHandler;
import com.lsh.ofc.core.redis.RedisTemplate;
import com.lsh.ofc.core.service.OfcCustomerService;
import com.lsh.ofc.core.service.OfcOrderService;
import com.lsh.ofc.provider.common.util.ValidationUtils;
import com.lsh.ofc.provider.rest.BaseService;
import com.lsh.ofc.proxy.model.Goods;
import com.lsh.ofc.proxy.service.AtpServiceProxy;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author peter
 */
@Service(protocol = "dubbo", validation = "true", timeout = 10000)
public class OrderServiceImpl extends BaseService implements OrderService, InitializingBean {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());


    @Autowired
    private OfcOrderService ofcOrderService;

    @Autowired
    private OfcCustomerService ofcCustomerService;

    @Autowired
    private MeipiCustomerHandler meipiCustomerHandler;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AtpServiceProxy atpServiceProxy;

    @Value("${order.weight.max}")
    private Double orderWeightMax;

    @Value("${psi.Path}")
    private String psiPath;

    @Value("${psi.bj.path}")
    private String psiBjPath;

    @Override
    public CommonResult<Boolean> createOrder(OrderHeadDTO dto) throws BusinessException {
        logger.info("create so:" + JSON.toJSONString(dto));
        ValidationUtils.valid(dto);
        Long orderCode = dto.getOrderCode();
        OfcOrderHead filter = new OfcOrderHead();
        filter.setOrderCode(orderCode);
        if (this.ofcOrderService.count(filter) > 0) {
            logger.info("重复创建SO，订单号=" + orderCode);
            return CommonResult.success(true);
        }

        Long venderId = dto.getVenderId();
        BigDecimal totalSkuQty = BigDecimal.ZERO;
        List<OfcOrderDetail> details = new ArrayList<>();
        for (OrderDetailDTO item : dto.getDetails()) {
            JSONObject ext = new JSONObject();
            ext.put(Constants.ORDER_D_DETAIL_ID, item.getDetailId().toString());
            ext.put(Constants.ORDER_D_TYPE, item.getGoodsType());
            ext.put(Constants.ORDER_ITEM_WEIGHT_FLAG, item.getIsWeighingGoods());
            ext.put(Constants.ORDER_ITEM_BARCODE, item.getGoodsBarCode());
            String goodsExtAttrs = item.getGoodsExtAttrs();
            if (!StringUtils.isBlank(goodsExtAttrs)) {
                JSONObject goodsExtAttrsJson = JSON.parseObject(goodsExtAttrs);
                String itemRemark = goodsExtAttrsJson.getString("remark");
                ext.put("remark", itemRemark);
            }
            BigDecimal skuQty = item.getSkuQty();
            OfcOrderDetail detail = new OfcOrderDetail();
            detail.setOrderCode(orderCode);
            detail.setItemCode(item.getItemCode());
            detail.setGoodsCode(item.getGoodsCode());
            detail.setGoodsName(item.getGoodsName());
            detail.setGoodsSaleUnit(item.getGoodsSaleUnit());
            detail.setGoodsPrice(item.getGoodsPrice());
            detail.setGoodsQty(item.getGoodsQty());
            detail.setGoodsAmount(item.getGoodsAmount());
            detail.setSkuCode(item.getSkuCode());
            detail.setSkuQty(skuQty);
            //TODO:数据组需要
            detail.setExt(ext.toJSONString());
            detail.setVenderId(venderId);
            details.add(detail);
            totalSkuQty = totalSkuQty.add(skuQty);
        }

        OfcOrderHead head = new OfcOrderHead();
        head.setOrderCode(orderCode);
        head.setVenderId(venderId);
        head.setRegionCode(dto.getRegionCode());
        head.setAddressCode(dto.getAddressCode());
        head.setOrderAmount(dto.getOrderAmount());
        head.setOrderTime(dto.getCreateTime());
        head.setTotalSkuOrderQty(totalSkuQty);
        head.setFulfillStatus(FulfillStatus.NEW.getValue());
        head.setDetails(details);
        Map<String, String> ext = new HashMap<>(5);
        // 设置 address_info
        this.builderDefaultDeliveryInfo(dto, head, ext);

        head.setOrderDistributionType(DistributionType.ORDER_SO.getCode());

        String orderExt = dto.getOrderExt();
        if (StringUtils.isNotBlank(orderExt)) {
            JSONObject orderJsonExt = JSON.parseObject(orderExt);
            // 物流模式
            ext.put(Constants.OFC_ORDER_LOGISTICS_MODE, orderJsonExt.getString(Constants.OFC_ORDER_LOGISTICS_MODE));
            // po信息
            ext.put("po_order_flag", ObjectUtils.toString(orderJsonExt.getString("poOrderFlag"), "0"));
            ext.put("po_id", ObjectUtils.toString(orderJsonExt.getString("poId"), ""));
            ext.put("po_supplier_code", ObjectUtils.toString(orderJsonExt.getString("supplierCode"), ""));
            ext.put("supplier_group_id", ObjectUtils.toString(orderJsonExt.getString("supplierGroupId"), "0"));
            ext.put("order_class", ObjectUtils.toString(orderJsonExt.getString("orderClass"), "NORMAL"));
        }

        head.setExt(JSON.toJSONString(ext));
        this.ofcOrderService.create(head, true);
        return CommonResult.success(true);
    }

    private void builderDefaultDeliveryInfo(OrderHeadDTO dto, OfcOrderHead head, Map<String, String> ext) throws BusinessException {
        JSONObject addressInfo = JSON.parseObject(dto.getAddressInfo());
        // TODO 云仓 2018-09-13
        Long parentCode = dto.getParentOrderCode();
        String orderDc = dto.getOrderDc();
        Integer providerId = dto.getProviderId();
        String providerName = dto.getProviderName();
        String parentHaveCloudChildren = dto.getParentHaveCloudChildren();
        if (providerId == null || parentCode == null || StringUtils.isBlank(orderDc)) {
            throw new BusinessException(EC.ERROR_PARAMS.getCode(), " providerId ParentOrderCode orderDc 必须有值");
        }

        addressInfo.put("parent_order_code", parentCode);
        addressInfo.put("order_dc", orderDc);
        addressInfo.put("provider_id", providerId);
        addressInfo.put("provider_name", providerName);
        addressInfo.put("parent_have_cloud_children", parentHaveCloudChildren);

        ext.put("parent_order_code", parentCode + "");
        ext.put("order_dc", orderDc);
        ext.put("provider_id", providerId + "");
        ext.put("provider_name", providerName + "");
        ext.put("parent_have_cloud_children", parentHaveCloudChildren);
        ext.put("order_weight", "0.00");
        ext.put("store_street_order", "0");
        // TODO 前置仓
        if (dto.getRegionCode().equals(Region.BEIJING_CG.getCode())) {
            Integer isInDmall = addressInfo.getInteger(Constants.ORDER_IS_IN_DMALL);
            Integer deliveryWay = addressInfo.getInteger(Constants.ORDER_DELIVERY_WAY);
            String preWarehouseCode = addressInfo.getString(Constants.ORDER_PRE_WAREHOUSE_CODE);
            String userGroupIds = addressInfo.getString(Constants.USER_GROUP_IDS);

            if (isStoreStreetOrder(userGroupIds, preWarehouseCode, dto.getOrderCode())) {
                // 数据组使用：多点配送订单中，需要区分商店街订单（运费等计算规则不同）
                ext.put("store_street_order", "1");
                deliveryWay = DistributionWay.SEED_2_DMALL.getValue();
            } else if (this.filterFulfillment(orderDc, deliveryWay, dto, ext)) {
                logger.warn("订单{} deliveryWay 有误", dto.getOrderCode());
                deliveryWay = DistributionWay.ORDER_2_USER.getValue();
                isInDmall = SecondDistribution.NO.getCode();
                preWarehouseCode = "0";

                addressInfo.put(Constants.ORDER_DELIVERY_WAY, DistributionWay.ORDER_2_USER.getValue());
                addressInfo.put(Constants.ORDER_IS_IN_DMALL, SecondDistribution.NO.getCode());
                addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_CODE, preWarehouseCode);
                addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_NAME, "");
            }

            if (null == deliveryWay || deliveryWay == 0) {
                deliveryWay = DistributionWay.ORDER_2_USER.getValue();

                addressInfo.put(Constants.ORDER_DELIVERY_WAY, DistributionWay.ORDER_2_USER.getValue());
                addressInfo.put(Constants.ORDER_IS_IN_DMALL, SecondDistribution.NO.getCode());
                addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_CODE, preWarehouseCode);
                addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_NAME, "");
            }
            if (null == isInDmall) {
                isInDmall = SecondDistribution.NO.getCode();
            }
            if (deliveryWay.equals(DistributionWay.ORDER_2_SHOP.getValue())) {
                // TODO: 18/6/28  暂时不去掉这个拦截，目前pms不支持订单到店，直接配送模式。
                throw new BusinessException(EC.ERROR_PARAMS.getCode(), "仓配模式暂时不支持");
            } else if (DistributionWay.isPms(deliveryWay)) {
                if (StringUtils.isBlank(preWarehouseCode) || preWarehouseCode.equals("0")) {
                    throw new BusinessException(EC.ERROR_PARAMS.getCode(), "前置仓配送信息为空");
                }
            }
            // TODO 二次配送标志 默认非前置仓 0 表示不是，1 表示是
            head.setSecondDistributionFlag(isInDmall);
            // TODO 1 订单到用户, 2 订单到店, 3 提种到店 (默认非前置仓，默认1 ，前置仓默认3)
            head.setDistributionWay(deliveryWay);
            // TODO: 无前置仓设置 0 ，前置仓ID非0（传前置仓ID)
            head.setPreWarehouseCode(preWarehouseCode);

            ext.put(Constants.ORDER_PRE_WAREHOUSE_NAME, addressInfo.getString(Constants.ORDER_PRE_WAREHOUSE_NAME));
        } else {
            addressInfo.put(Constants.ORDER_DELIVERY_WAY, DistributionWay.ORDER_2_USER.getValue());
            addressInfo.put(Constants.ORDER_IS_IN_DMALL, SecondDistribution.NO.getCode());
            addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_CODE, "0");
            addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_NAME, "");

            head.setSecondDistributionFlag(addressInfo.getInteger(Constants.ORDER_IS_IN_DMALL));
            head.setDistributionWay(addressInfo.getInteger(Constants.ORDER_DELIVERY_WAY));
            head.setPreWarehouseCode(addressInfo.getString(Constants.ORDER_PRE_WAREHOUSE_CODE));
            ext.put(Constants.ORDER_PRE_WAREHOUSE_NAME, addressInfo.getString(Constants.ORDER_PRE_WAREHOUSE_NAME));
        }

        head.setAddressInfo(addressInfo.toJSONString());
    }

    private Boolean filterFulfillment(String orderDc, Integer deliveryWay, OrderHeadDTO dto, Map<String, String> ext) {
        Boolean isMainDelivery = false;

        if (null == deliveryWay) {
            return isMainDelivery;
        }

        if (!(DistributionWay.ORDER_2_USER.getValue().equals(deliveryWay))) {
            Double orderWeight = 6.66;
            try {
                orderWeight = 6.66;
                //this.calOrderWeight(dto);
            } catch (Exception ex) {

                logger.error("请求进销存失败", ex);
            }

            if (null == orderWeight) {
                orderWeight = 6.66;
            }
            // TODO 临时处理
            ext.put("order_weight", orderWeight + "");

            logger.info("【{}】订单的重量是{}", dto.getOrderCode(), orderWeight);

            if (orderWeight.compareTo(orderWeightMax) >= 0) {
                isMainDelivery = true;
            }
        }

        return isMainDelivery;
    }

    /**
     * 商店街需求：如果是商店街订单，走多点配送
     *
     * @param userGroupIds
     * @param preWarehouseCode
     * @param orderCode
     * @return
     */
    private boolean isStoreStreetOrder(String userGroupIds, String preWarehouseCode, Long orderCode) {
        //商店街，如果是商店街订单，则必须走前置仓配送
        try {
            if (StringUtils.isEmpty(userGroupIds)) {
                return false;
            }

            if (StringUtils.isEmpty(preWarehouseCode) || "0".equals(preWarehouseCode)) {
                return false;
            }

            List<Integer> orderUserGroupIds = JSON.parseArray(userGroupIds, Integer.class);
            if (CollectionUtils.isEmpty(orderUserGroupIds)) {
                return false;
            }

            String userGroupIdsStr = this.redisTemplate.get(Constants.STORE_STREET_USER_GROUP_IDS);
            if (StringUtils.isNotEmpty(userGroupIdsStr)) {
                List<Integer> userGroupIdList = JSON.parseArray(userGroupIdsStr, Integer.class);

                // todo：用户所属组，必须能够全部catch到，才必须走前置仓
                if (userGroupIdList.containsAll(orderUserGroupIds)) {
                    logger.info("【{}】商店街需求：订单走前置仓配送！", orderCode);
                    return true;
                }
            }
        } catch (Exception e) {
            logger.error("判断是否是商店街用户组，异常", e);
        }

        return false;
    }

    /**
     * 计算订单重量
     *
     * @param dto
     * @return
     */
    private Double calOrderWeight(OrderHeadDTO dto) {
        Map<Long, Map<String, BigDecimal>> skuDcQtyMap = atpServiceProxy.querySkuDcQtyMap(dto.getOrderCode(),null);

        Map<Long, BigDecimal> skuQty = new HashMap<>();
        Map<String, Set<Long>> dcQtySkuCodesMap = new HashMap<>();
        for (OrderDetailDTO detail : dto.getDetails()) {
            Long skuCode = detail.getSkuCode();
            Long goodsCode = detail.getGoodsCode();
            BigDecimal realQty = detail.getSkuQty();
            if (skuQty.containsKey(goodsCode)) {
                BigDecimal totalRealQty = skuQty.get(goodsCode).add(realQty);
                skuQty.put(goodsCode, totalRealQty);
            } else {
                skuQty.put(goodsCode, realQty);
            }

            Map<String, BigDecimal> dcQtyMap = skuDcQtyMap.get(skuCode);
            for (Map.Entry<String, BigDecimal> entry : dcQtyMap.entrySet()) {
                Set<Long> goodsCodes = dcQtySkuCodesMap.get(entry.getKey());
                if (CollectionUtils.isEmpty(goodsCodes)) {
                    goodsCodes = new HashSet<>();
                    dcQtySkuCodesMap.put(entry.getKey(), goodsCodes);
                }
                goodsCodes.add(goodsCode);
            }
        }

        Map<Long, Goods> goodsInfoMap = new HashMap<>();
        Map<String, BigDecimal> supplySkuCodeWeightMap = new HashMap<>();
        for (Map.Entry<String, Set<Long>> entry : dcQtySkuCodesMap.entrySet()) {
            String[] split = entry.getKey().split(":");
            String dc = split[0];
            Integer supplyMarket = Integer.valueOf(split[1]);
            Integer supplyOrg = Integer.valueOf(split[2]);

            Map<Long, Goods> goodsInfo = new HashMap<>();
//            goodsServiceProxy.getGoodsInfoMapByGoodsCodes(entry.getValue(), supplyMarket, supplyOrg, dc);

            List<String> supplySkuCodeList = new ArrayList<>();
            for (Map.Entry<Long, Goods> goodsEntry : goodsInfo.entrySet()) {
                Goods good = goodsEntry.getValue();
                supplySkuCodeList.add(good.getSupplySkuCode());
            }
//            String supplySkuCodes = StringUtils.join(supplySkuCodeList.toArray(), ",");

            Map<String, BigDecimal> goodsWeight;
//            if (SupplierOrg.LSH.getValue().equals(supplyOrg)) {
//                goodsWeight = wgServiceProxy.getGoodsWeight(psiBjPath, supplySkuCodes, "2");
//            } else if (SupplierOrg.WG.getValue().equals(supplyOrg)) {
//                goodsWeight = wgServiceProxy.getGoodsWeight(psiBjPath, supplySkuCodes, "3");
//            } else {
//                goodsWeight = Collections.emptyMap();
//            }
            goodsWeight = Collections.emptyMap();

            supplySkuCodeWeightMap.putAll(goodsWeight);
            goodsInfoMap.putAll(goodsInfo);
        }

        BigDecimal totalWeight = BigDecimal.ZERO;
        for (Map.Entry<Long, BigDecimal> entry : skuQty.entrySet()) {
            Long goodCode = entry.getKey();
            BigDecimal realQty = entry.getValue();
            Goods good = goodsInfoMap.get(goodCode);
            BigDecimal weight = BigDecimal.ONE;
            if (null != good) {
                String supplySkuCode = good.getSupplySkuCode();

                weight = supplySkuCodeWeightMap.get(supplySkuCode);
                if (null == weight || weight.compareTo(BigDecimal.ZERO) <= 0) {
                    weight = BigDecimal.ONE;
                }
            }
            totalWeight = totalWeight.add(realQty.multiply(weight));
        }
        return totalWeight.doubleValue();
    }

    @Override
    public CommonResult<Boolean> cancelOrder(Long orderCode) throws BusinessException {
        this.ofcOrderService.cancel(orderCode);
        return CommonResult.success(true);
    }

    @Override
    public CommonResult<Boolean> cancelOrderNotify(Long orderCode) throws BusinessException {
        this.ofcOrderService.cancelNotify(orderCode);
        return CommonResult.success(true);
    }

    @Override
    public boolean isWumartOfc() throws BusinessException {
        return meipiCustomerHandler.isWumartOfc();
    }

    @Override
    public boolean isForceCancel(Long orderCode) throws BusinessException {
        return this.ofcOrderService.isForceCancel(orderCode);
    }

    /**
     * 校验并更新获取OFC客户信息
     *
     * @param order
     * @return
     * @throws BusinessException
     */
    private OfcCustomer getCustomer(OfcOrderHead order) throws BusinessException {
        //校验并更新用户信息
        JSONObject addressInfo = JSON.parseObject(order.getAddressInfo());
        OfcCustomer param = new OfcCustomer();
        param.setRegionCode(order.getRegionCode());
        param.setCustCode(order.getAddressCode());
        //超市名称
        param.setCustName(addressInfo.getString("market_name"));
        param.setProvince(addressInfo.getString("province_name"));
        param.setCity(addressInfo.getString("city_name"));
        param.setDistrict(addressInfo.getString("county_name"));
        param.setAddress(addressInfo.getString("address"));
        param.setContactName(addressInfo.getString("contact_name"));
        param.setContactPhone(addressInfo.getString("contact_phone"));
        //坐标
        param.setLocation(addressInfo.getString("real_position"));
        //大车限行
        Integer transLimit = addressInfo.getInteger("trans_limit");
        param.setExt(JSON.toJSONString(Collections.singletonMap(Constants.USER_ADDRESS_TRANS_LIMIT, transLimit)));
        return this.ofcCustomerService.updateCustomer(param);
    }

    @Override
    public void afterPropertiesSet() throws BusinessException {
        try {
            List<Integer> userGroupIds = new ArrayList<>();
            // TODO:商店街，用户组；目前只有一个，后续可能增加
            userGroupIds.add(9);

            String key = Constants.STORE_STREET_USER_GROUP_IDS;
            String value = JSON.toJSONString(userGroupIds);
            redisTemplate.set(key, value);
            logger.info("初始化，商店街的user_group_ids成功！！key：{}，value：{}", key, value);
        } catch (Exception e) {
            logger.error("初始化，商店街的user_group_ids失败！！", e);
        }
    }
}
